/**
 * @class UI-面板-访问面板
 * @author DuskyHuang
 * @description 支持天体的归类、排序和直接访问。
 * @todo 当前每个星云、星系等直接访问未被支持，后续打开……
 */

import { _decorator, Toggle, Node, Sprite, Layout, ScrollView, Animation, JsonAsset, instantiate, Prefab, Label } from 'cc';
import { Res } from 'const';
import { core, Mediator } from 'cfw';
import { UI } from 'notifications';
import { changeFrame } from 'helpers';
import { constStars, deepGalaxy, LogProxy, planetary, solar, ui } from 'proxies';
import { TabCard } from '../items/tab-card';
import { IIconData } from '../../celestial';
import { LabelI18n } from '../label-i18n';
const { ccclass, property } = _decorator;


@ccclass('cocosmos.visit-panel')
export class VisitPanel extends Mediator {

    @property({ group: 'TabSort', type: Sprite }) public title: Sprite = null;
    @property({ group: 'TabSort', type: ScrollView }) public scrollTab: ScrollView = null;
    @property({ group: 'TabSort', type: Node }) public tabList: Node = null;
    @property({ group: 'TabSort', type: Prefab }) public tabCardTemplate: Prefab = null;
    @property({ group: 'TabSort', type: Node }) public sortList: Node = null;

    @property({ group: 'Content', type: Layout }) public contentList: Layout = null;
    @property({ group: 'Content', type: ScrollView }) public scrollContent: ScrollView = null;
    @property({ group: 'Content', type: JsonAsset }) public json: JsonAsset = null;
    @property({ group: 'Content', type: Node }) public tipDev: Node = null;
    @property({ group: 'Content', type: Toggle }) public visible: Toggle = null;

    @property({ group: 'Dialog', type: Node }) public popDialog: Node = null;
    @property({ group: 'Dialog', type: LabelI18n }) public tipDest: LabelI18n = null;
    @property({ group: 'Dialog', type: Sprite }) public cancel: Sprite = null;
    @property({ group: 'Dialog', type: Label }) public cd: Label = null;

    protected onLoad(): void { this._init(); }
    protected onEnable(): void {
        this.changeSpriteLang();
        this.scrollTab.scrollToLeft();
        this.popDialog.active = false;
    }

    protected start(): void { this._setDefaults(); }

    private _init(): void {
        this._tabs = this.tabList.getComponentsInChildren(Toggle);
        this._tab_checked = this._tabs.head!;
        this._configs = this.json.json as visitTabConfigs;
        this._sorts = this.sortList.getComponentsInChildren(Toggle);
        this._anim = this.getComponent(Animation);
        this.on(UI.Popups.VISIT_CD, this.onPopVisitCD);
        this.popDialog.active = false;
    }

    protected onPopVisitCD(name: celestial, into: into): void {
        this._dest = { name, into };
        this.unscheduleAllCallbacks();
        this.popDialog.active = true;
        this._anim.play('visit-pop-out');
        this._cd = COUNT_DOWN;
        this.cd.string = `(${this._cd}s)`;
        this.tipDest.string = `celestial@${name}`;
        this.schedule(() => this._countDown(), 1);
    }

    private _countDown(): void {
        this._cd--;
        this.cd.string = `(${this._cd}s)`;
        if (this._cd <= 0) {
            this.unscheduleAllCallbacks();
            this.onClose(false);
        }
    }

    protected toggleTab(tab: Toggle): void {
        changeFrame(this._tab_checked.getComponent(Sprite), UI_POPS, 'dis', true);
        changeFrame(tab.getComponent(Sprite), UI_POPS, 'dis', false);
        this._tab_checked = tab;
        this._updateTab();
    }

    protected toggleVisible(tgl: Toggle): void {
        const visible = tgl.isChecked;
        changeFrame(tgl.getComponent(Sprite), UI_POPS, 'dis', !visible);
        this._updateVisible(visible);
    }

    private _setDefaults(): void {
        this._tabs.forEach((tab, idx) => changeFrame(tab.getComponent(Sprite), UI_POPS, 'dis', idx !== 0));
        this.scrollTab.scrollToLeft();
        this._updateTab();
    }

    protected changeSpriteLang(): void {
        const { language } = ui, en = language === 'en';
        changeFrame(this.cancel, UI_POPS, 'en', en);
        changeFrame(this.title, UI_POPS, 'en', en);
    }

    protected toggleSort(sort: Toggle): void {
        changeFrame(this._sort_checked.getComponent(Sprite), UI_POPS, 'dis', true);
        changeFrame(sort.getComponent(Sprite), UI_POPS, 'dis', false);
        this._sort_checked = sort;
        this._updateSort();
    }

    protected onClose(clear: boolean = true): void {
        if (clear) this._dest = null;
        this.notify(UI.Panels.CLOSE, this.node.name);
    }

    protected onHide(): void {
        if (notEmpty(this._dest)) {
            const { name, into } = this._dest;
            if (LogProxy.PRINT_VISIT) console.info('=>', UI.VISIT, name, into);
            core.notify(UI.VISIT, name, into);
        }
        this.node.removeFromParent();
    }

    protected onCancel(): void {
        this.unscheduleAllCallbacks();
        this._anim.play('visit-pop-in');
        this._dest = null;
    }

    protected onPopIn(): void {
        this.popDialog.active = false;
    }

    private _updateTab(): void {
        const into = this._into;
        // console.log('tab by:', into);
        const todo = TODO.contains(into);
        this.tipDev.active = todo;
        this.sortList.active = this.visible.node.active = !todo;
        if (todo) return this._freeCards();
        const config = this._configs[into ?? ''] as Values<visitTabConfigs>;
        if (config) {
            this._config = config;
            this._resetSortToggles();
            this._resetVisible();
            this._updateSort();
        }
    }

    private _updateVisible(visible: boolean): void {
        this.notify(this._notification, visible);
        this.notify(UI.VISIBLE, this._into_cn, visible, true);
    }

    private _resetSortToggles(): void {
        this._sorts.forEach(sort => sort.node.active = false);
        this._sort_checked = this._sorts.head;
        for (let i = 0; i < this._config.sorts.length; i++) {
            const by = this._config.sorts[i].by;
            const sort = this._sorts[i];
            sort.node.active = true;
            const sprite = sort.getComponent(Sprite);
            const head = i === 0;
            sprite.spriteFrame = core.res.getSheetFrame(UI_POPS, `sort_${by}${head ? '' : '-dis'}`);
            sort.setIsCheckedWithoutNotify(head);
            sort.node.name = by;
        }
    }

    private _resetVisible(): void {
        const { _into } = this;
        this._notification = Dict[_into] ?? '';
        this._into_cn = this._notification.split('.').tail;
        const visible = solar.getStateByName(this._into_cn) ?? planetary.getStateByName(this._into_cn) ??
            constStars.getStateByName(this._into_cn) ?? deepGalaxy.getStateByName(this._into_cn);
        this.visible.setIsCheckedWithoutNotify(visible);
        changeFrame(this.visible.getComponent(Sprite), UI_POPS, 'dis', !visible);
    }

    private _updateSort(): void {
        // console.info('sort by:', this._sort);
        const { icons, sorts } = this._config, { _into } = this;
        const idx = this._sort_checked.node.getSiblingIndex();
        const { by, cards } = sorts[idx];
        const useRank = cards.length <= 1;
        this._freeCards();
        for (let card of cards) {
            const { indexes, title } = card;
            const tabCard = this._claim();
            const dataList: IIconData[] = indexes.map((i, idx) => {
                return { into: _into, name: icons[i], pop: 'visit-cd', tag: (useRank && idx <= 4) ? ('rank_' + idx) : '' };
            });
            this.contentList.node.addChild(tabCard.node);
            const ttl = title ? (title.includes('@') ? title : `sorts@${title}`) : `sorts@${by}`;
            tabCard.updateData(ttl, dataList);
        }
        this.scrollContent.scrollToTop();
    }

    private _claim(): TabCard {
        return this._cards_pool.pop() ?? instantiate(this.tabCardTemplate)!.getComponent(TabCard);
    }

    private _freeCards(): void {
        this.contentList.getComponentsInChildren(TabCard).forEach(card => {
            card.clear();
            card.node.removeFromParent();
            this._cards_pool.push(card);
        });
    }

    private get _into(): into { return this._tab_checked?.node?.name as into; }
    private _notification: string = null;
    private _into_cn: string = null;
    private get _sort(): sort { return this._sort_checked?.node?.name as sort; }
    private _tabs: Toggle[] = [];
    private _configs: Partial<visitTabConfigs> = {};
    private _config: Values<visitTabConfigs> = null;
    private _cards_pool: TabCard[] = [];
    private _sorts: Toggle[];
    private _tab_checked: Toggle;
    private _sort_checked: Toggle;
    private _cd: time.sec = 3;
    private _dest: Partial<{ name: celestial, into: into }> = null;
    private _anim: Animation = null;
}

const { UI_POPS } = Res.Sheets;
const COUNT_DOWN: time.sec = 3;
const { Solar, Local, Stellar } = UI;
const TODO: into[] = ['constellation', 'artificial', 'nebula', 'cluster', 'galaxy'];
const Dict = {
    planet: Solar.PLANETS,
    satellite: Local.SATELLITES,
    dwarf: Solar.DWARFS,
    minor: Solar.MINORS,
    comet: Solar.COMETS,
    belts: Solar.BELTS,
    artificial: Local.ARTIFICIAL,
    // sun: Solar.SUN,
    star: Stellar.STARS,
    constellation: Stellar.CONSTS,
    nebula: Stellar.NEBULAS,
    cluster: Stellar.CLUSTERS,
    galaxy: Stellar.GALAXIES,
    blackhole: Stellar.BLACKHOLE,
};